import { Inject, Optional, Injectable } from '@angular/core';

import { ILayoutService } from '../inerface/layout-service.interface';
import { ComponentInfoModel } from '../model/component-info.model';
import { APP_NAME_TOKEN, PILOT_USERPROFILE_API_REGION_TOKEN } from '../constants';
import { IPilotProvider, PilotProvider, PILOT_PROVIDER } from 'wit-pilot-dataprovider';
import { ICONTEXT_BROKER_TOKEN } from 'p-elite-app-contextbroker';
import { Observable } from 'rxjs/Observable';
import { ContextService, LoggerService } from 'wit-core';
import { Observer } from "rxjs/Observer";

@Injectable()
export class LayoutService implements ILayoutService {

    private _userBackupComponents: ComponentInfoModel[];
    private _components: Map<string, ComponentInfoModel[]>;
    private _readOnlyMode: boolean;

    constructor(
        private _logger: LoggerService,
        @Inject(PILOT_PROVIDER) private _contextBroker: IPilotProvider,
        @Inject(APP_NAME_TOKEN) private _appName: string,
        @Inject(PILOT_USERPROFILE_API_REGION_TOKEN) @Optional() private _pilotApiRegion: string,
    ) {

    }

    getComponents(): Map<string, ComponentInfoModel[]> {
        return this._components;
    }

    getBackupComponents(): ComponentInfoModel[] {
        return this._userBackupComponents;
    }

    getComponentData(componentKey: string): Observable<ComponentInfoModel> {
        let query = `select * from componentInfo where componentKey = '${componentKey}'`;

        return this._contextBroker
            .query(query, )
            .map(r => new ComponentInfoModel(r))
            .take(1);
    }

    getUserComponents(targetUser?: string, componentType?: string): Observable<ComponentInfoModel> {
        let cmpWhere = componentType ? `and componentType='${componentType}'` : '';
        let query = `Select * from componentInfo where appName = '${this._appName}' and userName = '${targetUser}' and isBackup = false and isDeleteFlag = false ${cmpWhere}`;
        return this._contextBroker.query(query)
            .map(r => new ComponentInfoModel(r));
    }

    getUserComponentWithDefaults(targetUser: string, componentType?: string): Observable<ComponentInfoModel> {
        let cmpWhere = componentType ? `and componentType='${componentType}'` : '';
        let userWhere = targetUser ? `and userName in ('${targetUser}','ALL')` : '';
        let query = `Select * from componentInfo where appName = '${this._appName}' ${userWhere} and isBackup = false and isDeleteFlag = false ${cmpWhere}`;

        return this._contextBroker.query(query)
            .map(r => new ComponentInfoModel(r));
    }

    insertLayoutComponent(layoutComponent: ComponentInfoModel): Promise<boolean> {
        if (this._readOnlyMode) {
            this.internalLogError(`|Layout|FileLayouts Imported. ReadOnlyMode. Backend Insert Operation Not allowed: ${layoutComponent}`);
            return Promise.resolve(false);
        }

        delete (<any>layoutComponent)._iPComponentInfoBO;

        let proxyContext = this.composeUserProfileProxy('putUserProfileComponent', [layoutComponent]);

        return this._contextBroker
            .invokeProxy(proxyContext.className, proxyContext.methodName, proxyContext.arguments)
            .then(r => r as boolean);
    }

    deleteLayoutComponent(layoutComponentKey: string): Promise<boolean> {
        if (this._readOnlyMode) {
            this.internalLogError(`|Layout|FileLayouts Imported. ReadOnlyMode. Backend Insert Operation Not allowed: ${layoutComponentKey}`);
            return Promise.resolve(false);
        }
        let proxyContext = this.composeUserProfileProxy('removeUserProfileComponent', [layoutComponentKey]);
        return this._contextBroker
            .invokeProxy(proxyContext.className, proxyContext.methodName, proxyContext.arguments)
            .then(r => r as boolean);
    }

    renameLayoutComponent(newName: string, layoutComponentKey: string): Promise<boolean> {
        if (this._readOnlyMode) {
            this.internalLogError(`|Layout|FileLayouts Imported. ReadOnlyMode. Backend Insert Operation Not allowed: ${layoutComponentKey}`);
            return Promise.resolve(false);
        }

        let proxyContext = this.composeUserProfileProxy('RenameComponent', [newName, layoutComponentKey]);
        return this._contextBroker
            .invokeProxy(proxyContext.className, proxyContext.methodName, proxyContext.arguments)
            .then(r => r as boolean);
    }

    resetComponentDefaults(componentType: string): Promise<boolean> {
        if (this._readOnlyMode) {
            this.internalLogError(`|Layout|FileLayouts Imported. ReadOnlyMode. Backend Insert Operation Not allowed: ${componentType}`);
            return Promise.resolve(false);
        }
        let proxyContext = this.composeUserProfileProxy(' resetComponentDefaults', [ContextService.CurrentContext.user, componentType, this._appName]);
        return this._contextBroker
           .invokeProxy(proxyContext.className, proxyContext.methodName, proxyContext.arguments)
            .then(r => r as boolean);
    }

    createEntity(): ComponentInfoModel {
        let defaultCmpInfo = ComponentInfoModel.defaultFactory();
        let filledCmpInfo = this.fillDefaultCmpInfoModel(defaultCmpInfo)

        return filledCmpInfo;
    }

    importTemporaryLayouts(importEntities: ComponentInfoModel[]): void {

    }

    getReadOnlyMode(): boolean {
        return this._readOnlyMode;
    }

    private internalLogError(message: string, exception?: string) {
        this._logger.error(this.constructor.name, message, exception);
    }

    private composeUserProfileProxy(methodName: string, args: any[]): { className: string, methodName: string, arguments: any[] } {
        let proxyContext = {
            className: `${this._pilotApiRegion || DEFAULT_PILOT_REGION}.IPUserProfileProxy`,
            methodName: methodName,
            arguments: args,
        };

        return proxyContext;
    }

    private fillDefaultCmpInfoModel(cmpInfo: ComponentInfoModel) {
        let tmpCmpInfo = cmpInfo;
        tmpCmpInfo.appName = this._appName;
        tmpCmpInfo.userName = ContextService.CurrentContext.user;

        return tmpCmpInfo;
    }
}

const DEFAULT_PILOT_REGION = 'com.pingan.pilot.userprofile.api';